//-----------------------------------------------------------------------------


#define STRICT
#define DIRECTINPUT_VERSION 0x0800

//-----------------------------------------------------------------------------
// Include these files
#include <windows.h>	// Windows library (for window functions, menus, dialog boxes, etc)
#include <d3dx9.h>		// Direct 3D library (for all Direct 3D functions)
#include <dinput.h>		// Direct Input library (for Direct Input functions)
#include <stdlib.h>		// Maths conversion routines (floating point to string)
#include "D3DFont.h"	// The Direct3D font utility library
#include <string>		// String Library
//#include <fmod.hpp>		// for music :D
//-----------------------------------------------------------------------------
// Now let's start including our own classes now.
// Like our mesh class.
#include "Mesh.h"
#include "world.h"
#include "Player.h"
#include "CONSTANTS.h"
#include "Chest.h"
#include "NPC.h"
//-----------------------------------------------------------------------------
// Load in the XAnimator libraries
#include "XAnimator\XAnimator_lib.h"
// Debug graphics header
#include "XAnimator\DebugGraphics.h"

//-----------------------------------------------------------------------------
// Global variables

LPDIRECT3D9             g_pD3D              = NULL; // The D3D object
LPDIRECT3DDEVICE9       g_pd3dDevice        = NULL; // The rendering device

LPDIRECTINPUT8			g_pDI				= NULL; // The Direct Input object
LPDIRECTINPUTDEVICE8	g_pDIMouseDevice	= NULL; // The Direct Input mouse device.
LPDIRECTINPUTDEVICE8    g_pDIKeyboardDevice = NULL; // The Direct Input keyboard device.

// Global variables

D3DXMATRIX TranslateMat;
D3DMATERIAL9 Mtl;
CD3DFont *g_Font;   // The font for instruction text.
int WindowWidth(1024), WindowHeight(768); //ScreenRes

// XAnimation bits and bats. Does nothing so far, I guess.
IXAnimator *gXAnimator=0;

// Sprites Stuff
LPD3DXSPRITE			g_pMsgBoxSpr	 = NULL; // inits a sprite.
LPDIRECT3DTEXTURE9		g_pTexture1		 = NULL; // The texture.
LPD3DXSPRITE			g_pMenuBoxSpr	 = NULL; // inits a sprite.
LPDIRECT3DTEXTURE9		g_pMenuTexture	 = NULL; // The texture.
LPD3DXSPRITE			g_pPointerSpr	 = NULL; // inits a sprite.
LPDIRECT3DTEXTURE9		g_pPointerTexture= NULL; // The texture.

LPD3DXSPRITE			g_pHeroSpr	     = NULL; // inits a sprite.
LPDIRECT3DTEXTURE9		g_pHeroTexture   = NULL; // The texture.
LPD3DXSPRITE			g_pKnightSpr	 = NULL; // inits a sprite.
LPDIRECT3DTEXTURE9		g_pKnightTexture = NULL; // The texture.
LPD3DXSPRITE			g_pWizardSpr	 = NULL; // inits a sprite.
LPDIRECT3DTEXTURE9		g_pWizardTexture= NULL; // The texture.
D3DXVECTOR3 MsgBoxPos,origin(0,0,0),MenuBoxPos, pointerPos((WindowWidth/2),(WindowHeight/2),0),pointerOrigin(49,5,0);


bool MenuBoxDraw(false);
bool DownPressed(false);
std::string OUTPUT_MSG;
int GAMESTATE(0);
//camera positions
float g_camX(0.0f), g_camZ(0.0f);
// Function Prototypes
void WINAPI CleanUpDirectInput();
void CleanUp();
// Camera positioning
D3DXVECTOR3 CameraPosition, TargetPosition;

bool InteractPressed = false;

World TheWorld(g_pd3dDevice);
Player PlayerChar(g_pd3dDevice, &TheWorld);
int CURRENT_LEVEL(TOWNMAP);

	ChestsS ChestArray[10] = 
	{
	//row = chestID
	// itemID, quantity, opened?, x, z ,yrot 	
		{MONEY,200,false, 100, 100 ,90},
		{POTION,200,false, 25, 25 ,0},
		{BITCHES,200,false, 100, 50 ,0},
		{MONEY,200,false, 50, 25 ,0},
		{MONEY,200,false, 50, 50 ,0},
		{MONEY,200,false, 50, 50 ,0},
		{MONEY,200,false, 50, 50 ,0},
		{MONEY,200,false, 50, 50 ,0},
		{MONEY,200,false, 50, 50 ,0},
		{MONEY,200,false, 50, 50 ,0},
	};

//-----------------------------------------------------------------------------
// Set up the scene geometry.
void SetupFonts()
{
	//AddFontResource("nesfont.ttf");
	g_Font = new CD3DFont("Times New Roman", 20, NULL);
	g_Font -> InitDeviceObjects(g_pd3dDevice);
	g_Font -> RestoreDeviceObjects();
}

HRESULT SetupSprites()
{
	if (SUCCEEDED(D3DXCreateSprite(g_pd3dDevice,&g_pMsgBoxSpr)))
	{
		D3DXCreateTextureFromFile(g_pd3dDevice, "MessageBox.tga", &g_pTexture1);
		MsgBoxPos.x=(WindowWidth / 2) - 250;
		MsgBoxPos.y= WindowHeight - 50;
		MsgBoxPos.z=0.0f;
		
	}
	if (SUCCEEDED(D3DXCreateSprite(g_pd3dDevice,&g_pMenuBoxSpr)))
	{
		D3DXCreateTextureFromFileEx(g_pd3dDevice, "MenuBox800600.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT, 0, D3DFMT_R8G8B8, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &g_pMenuTexture);
		MenuBoxPos.x = (WindowWidth / 2) - 400;
		MenuBoxPos.y = (WindowHeight / 2) - 300;
		MenuBoxPos.z = 0;
	}
	if (SUCCEEDED(D3DXCreateSprite(g_pd3dDevice,&g_pPointerSpr)))
		D3DXCreateTextureFromFileEx(g_pd3dDevice, "pointer.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &g_pPointerTexture);

	if (SUCCEEDED(D3DXCreateSprite(g_pd3dDevice,&g_pHeroSpr)))
		D3DXCreateTextureFromFile(g_pd3dDevice, "HeroSpr.png", &g_pHeroTexture);

	if (SUCCEEDED(D3DXCreateSprite(g_pd3dDevice,&g_pWizardSpr)))
		D3DXCreateTextureFromFile(g_pd3dDevice, "wizardSpr.png", &g_pWizardTexture);

	if (SUCCEEDED(D3DXCreateSprite(g_pd3dDevice,&g_pKnightSpr)))
		D3DXCreateTextureFromFile(g_pd3dDevice, "knightSpr.png", &g_pKnightTexture);
	return S_OK;
}
//-----------------------------------------------------------------------------
// Initialise Direct 3D.
HRESULT SetupD3D(HWND hWnd)
{
    // Create the D3D object, return failure if this can't be done.
    if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) return E_FAIL;

    // Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
	d3dpp.MultiSampleType = D3DMULTISAMPLE_8_SAMPLES;
	d3dpp.MultiSampleQuality = 2;


    // Create the D3D Device
    if (FAILED(g_pD3D -> CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice))) return E_FAIL;

	// Enable the lighting.
	g_pd3dDevice -> SetRenderState(D3DRS_LIGHTING, TRUE);

	// Turn on D3D depth buffer to ensure polygons are rendered correctly according to their depth
	g_pd3dDevice -> SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);

    // Turn on D3D backface culling to ensure both faces of triangles are rendered (clockwise & anti-clockwise)
    g_pd3dDevice -> SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
	g_pd3dDevice -> SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);

	//Let's load up XAnimator.
	gXAnimator = CreateXAnimator(g_pd3dDevice);
	STARTUP_DBGFX();
	DBG_GFX.Initialise(g_pd3dDevice);
	g_pd3dDevice -> SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); 
	g_pd3dDevice -> SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
	g_pd3dDevice -> SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
	g_pd3dDevice -> SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 16);
	g_pd3dDevice ->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
	// Set up the fonts
	SetupFonts();
	// set up sprite
	SetupSprites();
	// Load the player!
	PlayerChar.loadModelXA(gXAnimator, g_pd3dDevice,"CharModel1.X");
	// Setup the world's pointers
	TheWorld.LoadPointers(g_pd3dDevice, gXAnimator, &ChestArray[0],&GAMESTATE, &OUTPUT_MSG, &PlayerChar);

    return S_OK;
}

//-----------------------------------------------------------------------------
// Terminate Direct Input and clean up (always unacquire device before calling Release())
void WINAPI CleanUpDirectInput()
{
    if (g_pDI != NULL)
    {
        // Release the mouse.
		if (g_pDIMouseDevice != NULL)
        {
            g_pDIMouseDevice -> Unacquire();
            g_pDIMouseDevice -> Release();
            g_pDIMouseDevice = NULL;
        }

		// Release the keyboard
		if (g_pDIKeyboardDevice != NULL)
        {
            g_pDIKeyboardDevice -> Unacquire();
            g_pDIKeyboardDevice -> Release();
            g_pDIKeyboardDevice = NULL;
        }

		// Release the Direct Input Object.
		g_pDI -> Release();
        g_pDI = NULL;
    }
}

//-----------------------------------------------------------------------------
// Release (delete) all the resources used by this program.
VOID CleanUp()
{
	SHUTDOWN_DBGFX();
    CleanUpDirectInput();

	if (gXAnimator !=NULL)
	{
		gXAnimator = 0;
	}

	if (g_Font != NULL) delete g_Font;

    if (g_pd3dDevice != NULL)
	{
		g_pd3dDevice -> Release();
		g_pd3dDevice = NULL;
	}

    if (g_pD3D != NULL)	
	{
		g_pD3D -> Release();
		g_pD3D = NULL;
	}

	if (g_pMsgBoxSpr != NULL)
	{
		g_pMsgBoxSpr -> Release();
		g_pMsgBoxSpr = NULL;
	}
		if (g_pTexture1 != NULL)
	{
		g_pTexture1 -> Release();
		g_pTexture1 = NULL;
	}
}

//-----------------------------------------------------------------------------
// Set up the scene geometry.
HRESULT SetupGeometry(int CURRENT_LEVEL)
{
	TheWorld.loadMap(CURRENT_LEVEL);

	return S_OK;
}

//-----------------------------------------------------------------------------
// Set up the view - the view and projection matrices.
void SetupViewMatrices()
{
	// Set up the view matrix.
	// This defines which way the 'camera' will look at, and which way is up.
	TargetPosition.x = (cos(PlayerChar.Yrot + D3DXToRadian(270)) * 75) + PlayerChar.x;
	TargetPosition.z = (sin(PlayerChar.Yrot + D3DXToRadian(90)) * 75) + PlayerChar.z;
	TargetPosition.y = 40;
	// moving the camera position behind the player :)
	if (CameraPosition.x < TargetPosition.x)
	{
		CameraPosition.x += CAM_SPD;
		if (CameraPosition.x > TargetPosition.x)
			CameraPosition.x = TargetPosition.x;
	}

	if (CameraPosition.x > TargetPosition.x)
	{
		CameraPosition.x -= CAM_SPD;
		if (CameraPosition.x < TargetPosition.x)
			CameraPosition.x = TargetPosition.x;
	}

	if (CameraPosition.z < TargetPosition.z)
	{
		CameraPosition.z += CAM_SPD;
		if (CameraPosition.z > TargetPosition.z)
			CameraPosition.z = TargetPosition.z;
	}

	if (CameraPosition.z > TargetPosition.z)
	{
		CameraPosition.z -= CAM_SPD;
		if (CameraPosition.z < TargetPosition.z)
			CameraPosition.z = TargetPosition.z;
	}

	CameraPosition.y = TargetPosition.y;
    D3DXVECTOR3 vCamera(CameraPosition);
    D3DXVECTOR3 vLookat(PlayerChar.x, 35.0f, PlayerChar.z);
    D3DXVECTOR3 vUpVector(0.0f, 1.0f, 0.0f);
    D3DXMATRIX matView;
    D3DXMatrixLookAtLH( &matView, &vCamera, &vLookat, &vUpVector);
    g_pd3dDevice -> SetTransform(D3DTS_VIEW, &matView);


	// Calculate pictur aspect ratio. This does differ dpending on widescreen stuff
	float AspectRatio(0.0f); 
	AspectRatio = static_cast<float>(WindowWidth)/(WindowHeight);
	// Set up the projection matrix.
	// This transforms 2D geometry into a 3D space.
    D3DXMATRIX matProj;
    D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4,AspectRatio, 1.0f, 4000.0f);
	//D3DXMatrixOrthoLH(&matProj, 200, 200, -100.0f, 1000.0f);
    g_pd3dDevice -> SetTransform(D3DTS_PROJECTION, &matProj);
}


//------------------------------------------------------------------------------

void SetupLights()
{
	g_pd3dDevice -> SetRenderState( D3DRS_AMBIENT, D3DCOLOR_XRGB(213,237,237) );
    D3DLIGHT9 MainEnvironmentLight;
    ZeroMemory(&MainEnvironmentLight, sizeof(D3DLIGHT9));
    MainEnvironmentLight.Type = D3DLIGHT_DIRECTIONAL;

	MainEnvironmentLight.Diffuse.r = 1.0f;
	MainEnvironmentLight.Diffuse.g = 1.0f;
	MainEnvironmentLight.Diffuse.b = 0.835f;

	MainEnvironmentLight.Direction = D3DXVECTOR3(-1, -1, 0); // Light points along -ve X axis.

	// Select and enable the light.
    g_pd3dDevice -> SetLight(0, &MainEnvironmentLight);
    g_pd3dDevice -> LightEnable(0, TRUE);


}

void SetupMaterial(float r, float g, float b)
{

}

//-----------------------------------------------------------------------------
// Render the scene.
void Render()
{
    // Clear the backbuffer to a black color
    g_pd3dDevice -> Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);

    // Begin the scene
    if (SUCCEEDED(g_pd3dDevice -> BeginScene()))
    {

		if(GAMESTATE == MENU)
		{
			g_pMenuBoxSpr -> Begin(D3DXSPRITE_ALPHABLEND);
			g_pMenuBoxSpr -> Draw(g_pMenuTexture, NULL,&origin, &MenuBoxPos, 0xFFFFFFFF);
			g_pMenuBoxSpr -> End();

			D3DXVECTOR3 tempPos(MenuBoxPos.x + 30,MenuBoxPos.y + 30,0);
			g_pHeroSpr -> Begin(D3DXSPRITE_ALPHABLEND);
			g_pHeroSpr -> Draw(g_pHeroTexture, NULL,&origin,&tempPos, 0xFFFFFFFF);
			g_pHeroSpr -> End();

			D3DXVECTOR3 tempPos2(MenuBoxPos.x + 30,MenuBoxPos.y + 188,0);

			g_pKnightSpr -> Begin(D3DXSPRITE_ALPHABLEND);
			g_pKnightSpr -> Draw(g_pKnightTexture, NULL,&origin,&tempPos2, 0xFFFFFFFF);
			g_pKnightSpr -> End();

			D3DXVECTOR3 tempPos3(MenuBoxPos.x + 30,MenuBoxPos.y + 346,0);

			g_pWizardSpr -> Begin(D3DXSPRITE_ALPHABLEND);
			g_pWizardSpr -> Draw(g_pWizardTexture, NULL,&origin,&tempPos3, 0xFFFFFFFF);
			g_pWizardSpr -> End();

			g_Font -> DrawText(MenuBoxPos.x + 620, MenuBoxPos.y + 30 , D3DCOLOR_ARGB(100, 100, 100, 100), _T("Inventory"));
			g_Font -> DrawText(MenuBoxPos.x + 620, MenuBoxPos.y +70 , D3DCOLOR_ARGB(100, 100, 100, 100), _T("Magika"));
			g_Font -> DrawText(MenuBoxPos.x + 620, MenuBoxPos.y +110 , D3DCOLOR_ARGB(100, 100, 100, 100), _T("Equipment"));
			g_Font -> DrawText(MenuBoxPos.x + 620, MenuBoxPos.y +150 , D3DCOLOR_ARGB(100, 100, 100, 100), _T("Status"));
			g_Font -> DrawText(MenuBoxPos.x + 620, MenuBoxPos.y +190 , D3DCOLOR_ARGB(100, 100, 100, 100), _T("Config"));
			g_Font -> DrawText(MenuBoxPos.x + 620, MenuBoxPos.y +230 , D3DCOLOR_ARGB(100, 100, 100, 100), _T("Save"));

			g_pPointerSpr -> Begin(D3DXSPRITE_ALPHABLEND);
			g_pPointerSpr -> Draw(g_pPointerTexture, NULL,&pointerOrigin, &pointerPos, 0xFFFFFFFF);
			g_pPointerSpr -> End();
		}
		else
		{
		// ----- MAIN RENDER CODE-------
		// -----THIS RENDERS THE MAIN GAME--
			TheWorld.Render();
			PlayerChar.RenderXA();

			for (int i(0); i < TheWorld.Chests.size(); ++i)
			{
				Chest Temp(TheWorld.Chests[i]);
				Temp.RenderXA();
			}
			for (int i(0); i < TheWorld.NPCs.size(); ++i)
			{
				NPC Temp(TheWorld.NPCs[i]);
				Temp.RenderXA();
			}
		}
		// End the scene.
		if (GAMESTATE == DIALOGUE)
		{
			g_pMsgBoxSpr -> Begin(D3DXSPRITE_ALPHABLEND);
			D3DXVECTOR2 MsgBoxScaling(0.756,0.756);
			D3DXMATRIX  MsgBoxScale;
			D3DXMatrixTransformation2D(&MsgBoxScale,NULL,0.0,&MsgBoxScaling,NULL,NULL,NULL);
			g_pMsgBoxSpr -> SetTransform(&MsgBoxScale);
			g_pMsgBoxSpr -> Draw(g_pTexture1, NULL, &origin, &MsgBoxPos, 0xFFFFFFFF);
			g_pMsgBoxSpr -> End();
			g_Font -> DrawText(MsgBoxPos.x - 70 ,MsgBoxPos.y - 150, D3DCOLOR_ARGB(255, 255, 255, 255), _T(OUTPUT_MSG.c_str()));
		}

        g_pd3dDevice -> EndScene();
    }

    // Present the backbuffer to the display.
    g_pd3dDevice -> Present(NULL, NULL, NULL, NULL);
}

//------------------------------------------------------------------------------
// Initialise Direct Input (& terminate initialisation if an error is detected.)
BOOL WINAPI SetupDirectInput(HINSTANCE g_hinst, HWND g_hwndMain)
{
    HRESULT hr;

    // Create the DirectInput object.
    hr = DirectInput8Create(g_hinst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&g_pDI, NULL);
    if FAILED(hr) return FALSE;

	// Initialise the mouse...
    // Retrieve a pointer to an IDirectInputDevice8 interface for the mouse.
    hr = g_pDI -> CreateDevice(GUID_SysMouse, &g_pDIMouseDevice, NULL);
    if FAILED(hr)
    {
        CleanUpDirectInput();
        return FALSE;
    }

    // Now that you have an IDirectInputDevice8 interface, get ready to use it.
    // Set the data format using the predefined mouse data format.
    hr = g_pDIMouseDevice -> SetDataFormat(&c_dfDIMouse2);
    if FAILED(hr)
    {
        CleanUpDirectInput();
        return FALSE;
    }

    // Set the cooperative level
    hr = g_pDIMouseDevice -> SetCooperativeLevel(g_hwndMain, DISCL_FOREGROUND | DISCL_EXCLUSIVE);
    if FAILED(hr)
    {
        CleanUpDirectInput();
        return FALSE;
    }

	g_pDIMouseDevice -> Acquire();

	// Initialise the keyboard...
    // Retrieve a pointer to an IDirectInputDevice8 interface.
    hr = g_pDI -> CreateDevice(GUID_SysKeyboard, &g_pDIKeyboardDevice, NULL);
    if FAILED(hr)
    {
        CleanUpDirectInput();
        return FALSE;
    }

    // Set the data format using the predefined mouse data format.
    hr = g_pDIKeyboardDevice -> SetDataFormat(&c_dfDIKeyboard);
    if FAILED(hr)
    {
        CleanUpDirectInput(); // Terminate Direct Input initialisation if an error is detected.
        return FALSE;
    }

    // Set the cooperative level
    hr = g_pDIKeyboardDevice -> SetCooperativeLevel(g_hwndMain, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
    if FAILED(hr)
    {
        CleanUpDirectInput();
        return FALSE;
    }

    return TRUE;
}

//-----------------------------------------------------------------------------
// Process mouse inputs.
void WINAPI ProcessMouseInput()
{
    DIMOUSESTATE2 MouseState;      // DirectInput mouse state structure

    if (g_pDIMouseDevice != NULL)
	{
		// Get the input's device state and store it in 'MouseState'
	    ZeroMemory(&MouseState, sizeof(MouseState));
		HRESULT hr;
		hr = g_pDIMouseDevice -> GetDeviceState(sizeof(DIMOUSESTATE2), &MouseState);
		if (FAILED(hr))
		{
			// DirectInput may be telling us that the input stream has been
			// interrupted.  We aren't tracking any state between polls, so
			// we don't have any special reset that needs to be done.
			// We just re-acquire and try again.

			// If input is lost, then try to acquire and keep trying until acquired...
			hr = g_pDIMouseDevice -> Acquire();
			while (hr == DIERR_INPUTLOST)
			{
				hr = g_pDIMouseDevice -> Acquire();
			}
			hr = g_pDIMouseDevice -> GetDeviceState(sizeof(DIMOUSESTATE2), &MouseState);
		}

		if(GAMESTATE == MENU)
		{
			if (MouseState.lX != 0)
			{
				pointerPos.x += MouseState.lX;
			}

			if (MouseState.lY != 0)
			{
				pointerPos.y += MouseState.lY;
			}

				if(pointerPos.x > WindowWidth)
					pointerPos.x = WindowWidth;
				if(pointerPos.x < 0)
					pointerPos.x = 0;


				if(pointerPos.y > WindowHeight)
					pointerPos.y = WindowHeight;
				if(pointerPos.y < 0)
					pointerPos.y = 0;
		}
	
	}
}

//------------------------------------------------------------------------------------------
// Process keyboard inputs...
void WINAPI ProcessKeyboardInput()
{
	// Define a macro to represent the key detection predicate.
	#define KEYDOWN(name, key) (name[key] & 0x80)

 	// Create a buffer (memory space) to contain the key press data from the keyboard.
	char     buffer[256];
	HRESULT  hr;

    // Clear the keyboard data buffer - just in case.
	ZeroMemory(buffer, 256);

    // What is the current state of the keyboard?
	hr = g_pDIKeyboardDevice -> GetDeviceState(sizeof(buffer),(LPVOID)&buffer);
	if FAILED(hr)
	{
		// If this failed, the device has probably been lost.
		// Check for (hr == DIERR_INPUTLOST) and attempt to reacquire it here.
		hr = g_pDIKeyboardDevice -> Acquire();
        while (hr == DIERR_INPUTLOST)
		{
			hr = g_pDIKeyboardDevice -> Acquire();
		}
		hr = g_pDIKeyboardDevice -> GetDeviceState(sizeof(buffer),(LPVOID)&buffer);
	}

	// Check that the specific keys been pressed



	if(GAMESTATE == DIALOGUE)
	{
		if(KEYDOWN(buffer, DIK_E))
		{
			if(!InteractPressed)
			{
				GAMESTATE = NORMAL;
				InteractPressed = true;
			}
		}
		else
			InteractPressed = false;
	}

	if(GAMESTATE == NORMAL)
	{
		if(!KEYDOWN(buffer, DIK_SPACE) && !KEYDOWN(buffer, DIK_LEFT) && !KEYDOWN(buffer, DIK_RIGHT) && !KEYDOWN(buffer, DIK_DOWN))
			PlayerChar.Movement(0);

		if(KEYDOWN(buffer, DIK_S))
		{
			if(!DownPressed)
				PlayerChar.Yrot += D3DXToRadian(180);

			if(KEYDOWN(buffer, DIK_LSHIFT))
				PlayerChar.Movement(2);
			else
				PlayerChar.Movement(1);

			DownPressed = true;
		}
		else
		{
			DownPressed = false;
		}

		if(KEYDOWN(buffer, DIK_W))
		{
			if(KEYDOWN(buffer, DIK_LSHIFT))
				PlayerChar.Movement(2);
			else
				PlayerChar.Movement(1);
		}

		if(KEYDOWN(buffer, DIK_D))
			PlayerChar.Yrot += 0.05;

		if(KEYDOWN(buffer, DIK_A))
			PlayerChar.Yrot -= 0.05;

		if(KEYDOWN(buffer, DIK_SPACE))
			PlayerChar.Jump();

		if(KEYDOWN(buffer, DIK_E))
		{
			if(!InteractPressed)
			{
				PlayerChar.Interact();
				InteractPressed = true;
			}
		}
		else
			InteractPressed = false;

			// End application with 'Esc'
		if (KEYDOWN(buffer, DIK_ESCAPE))
		{
			if(!MenuBoxDraw)
			{
			// 'ESC' has been pressed - so tell the application to exit.
			PostQuitMessage(0);
			}
		}
		else
			MenuBoxDraw = false;
		if(KEYDOWN(buffer, DIK_M))
			GAMESTATE = MENU;
	}

	if(GAMESTATE == MENU)
	{
		if(KEYDOWN(buffer, DIK_ESCAPE))
		{
			GAMESTATE = NORMAL;
			MenuBoxDraw = true;
		}
	}
	
	if(KEYDOWN(buffer, DIK_1)){
		CURRENT_LEVEL = TOWNMAP;
		if (FAILED(SetupGeometry(CURRENT_LEVEL)))
		{
			PostQuitMessage(0);
		}
	}

		if(KEYDOWN(buffer, DIK_2)){
		CURRENT_LEVEL = TESTMAP;
		if (FAILED(SetupGeometry(CURRENT_LEVEL)))
		{
			PostQuitMessage(0);
		}
	}

	if(KEYDOWN(buffer, DIK_3)){
		CURRENT_LEVEL = INNMAP;
		if (FAILED(SetupGeometry(CURRENT_LEVEL)))
		{
			PostQuitMessage(0);
		}
	}
}


void PlayerInput()
{
	ProcessKeyboardInput();
	ProcessMouseInput();
}
//-----------------------------------------------------------------------------
// The window's message handling function.
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_DESTROY:
		{
            // Respond to a Windows destroy event.
			// Usually generated by clicking on the close box on the window.
            PostQuitMessage(0);
            return 0;
		}
	}

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

//-----------------------------------------------------------------------------
// WinMain() - The application's entry point.
// This sort of procedure is mostly standard, and could be used in most DirectX applications.
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int)
{
    // Register the window class
    WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, "Game", NULL};
    RegisterClassEx(&wc);

    // Create the application's window
	HWND hWnd = CreateWindow( "Game", "Game - Press Esc to Exit",
                              WS_OVERLAPPEDWINDOW, 0, 0, WindowWidth, WindowHeight,
                              GetDesktopWindow(), NULL, wc.hInstance, NULL);

	// Create and initialise FMOD::System object
	//FMOD::System *system = nullptr;
	//FMOD::System_Create(&system);
	//system->init(100, FMOD_INIT_NORMAL, 0);

    // Initialise Direct3D
    if (SUCCEEDED(SetupD3D(hWnd)))
    {
        // Create the scene geometry
        if (SUCCEEDED(SetupGeometry(CURRENT_LEVEL)))
        {
			// Initialise Direct Input and acquire the keyboard
			if (SUCCEEDED(SetupDirectInput(hInst, hWnd)))
			{
				// Show the window
				ShowWindow(hWnd, SW_SHOWDEFAULT);
				UpdateWindow(hWnd);

				// Set up the light.
				SetupLights();

				// Define the viewpoint.
				SetupViewMatrices();

				// Enter the message loop
				MSG msg;
				ZeroMemory(&msg, sizeof(msg));
				while (msg.message != WM_QUIT)
				{
					if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
					{
						TranslateMessage(&msg);
						DispatchMessage(&msg);
					}
					else
					{
						PlayerChar.Physics();
						SetupViewMatrices();
						Render();
						PlayerInput();
					}
				}
            }
        } 
    }
	CleanUp();

    UnregisterClass("Game", wc.hInstance);
    return 0;
}
